package com.cskaoyan.javase._1interface._0introduction;

import javafx.animation.Animation;

/**
 * 接口的引入
 * 现在我们有了新需求：一部分猫和狗，经过了特殊训练，能够直立行走了。
 * 那么这群特殊的猫和狗，怎么描述它们呢？
 *
 * 分析：
 * 部分猫和狗经过特殊训练，才能够直立行走。
 * 所以不可能直接加个方法到Cat类和Dog类中，不是所有猫狗都有这个行为。
 * 而特殊的猫狗仍然是猫和狗，所以它们肯定还要继承猫和狗这两个类。可能很多同学，这时候想到的就是：重新定义两个新的猫狗类（比如超级狗和猫）继承猫狗，然后给出直立行走的方法就算完事了。
 * 这样做不是不行，需求是实现了，但还有一些小问题：
 *      1.一方面没有体现代码复用。
 *      2.更重要的是，没有体现出特殊训练的过程。
 * 假如还有一些动物也要直立行走，增加这个行为，如何体现出规范性、标准性呢？
 * 体现出它们是特殊的经过训练的动物呢？
 *
 * 这里我们想到了抽象类，因为抽象类中抽象方法，可以强制约束子类实现它，这样就是一种标准和规范，体现了它经过了特殊训练，和之前不同了。
 *
 * 于是我们定义抽象类，给出抽象方法，让超级猫狗类去继承这个抽象类，可行吗？
 *
 * 理想很美好，现实很骨感。
 * 显然做不到，因为Java不支持多继承。
 * 除开这点这么做也不是完美的，问题是：
 *
 * 这个抽象类里面是对功能和行为的抽象，缺少属性（单独一个直立行走的行为是一个什么对象？）所以单独的行为不应该被抽象为类，不符合类的定义。
 * 继承这个抽象类也不符合继承的"is-a"关系，
 * 总之这里不适用继承（还是上面那句话，行为根本不是个体）
 * 并且使用类(普通类/抽象类)做这个事情,都是不合适的
 * 于是，我们就迫切需要一种全新的数据类型，这种全新的数据类型：
 *      1.不强调属性，只强调行为的抽象，"继承"它表示功能的扩展。
 *      2.在一个类继承某个类后，还能继续"继承"，不受Java单继承限制。
 *      3.没有"is-a"这种继承关系的限制。
 *      4.最好还有抽象方法。（因为它能表示规范和标准）
 *
 * 以上这种全新的数据类型，相比较于类class更加灵活的去使用的数据类型,就是接口（interface）。
 *
 * 接口的语法:
 * [访问权限修饰符] interface 接口名{}
 *
 * 解释:
 *      接口和类class是同等级别的数据类型,接口不是类
 *      1.定义class和定义interface的语法很相像,定义的位置也是一样,使用的访问权限修饰符也是一样,只有两种访问级别.
 *      2.interface关键字表示定义接口
 *      3.接口名和类名一样,大驼峰命名,见名知意...
 *          接口名某些程序员喜欢在名字之前,加一个大写"I",表示这是一个接口
 *      4.接口中是允许定义抽象方法的,和抽象类一样.
 *
 *      5.接口的"继承"
 *          一个普通类"继承"接口,更准确的说法是"实现"接口,它并不使用extends关键字,而是使用implements关键字
 *          但实际上不管是实现,还是继承
 *          它们仍然是父子关系
 *          普通类实现接口
 *          接口是父接口/父类
 *          普通类是子类/实现类
 *
 *      6.普通类实现接口 仍需实现接口中所有的抽象方法
 *
 * 接口的实现细节问题:
 *      1.如果一个类继承类又实现接口,那么先继承再实现
 *      2.接口不受单继承限制,表现在两点:
 *          a.一个类可以继承类的同时实现接口
 *          b.一个类可以实现多个接口
 *
 * 使用接口有如下优点：
 *      1.接口不受单继承限制，这是接口非常重要的优点。
 *      2.接口不是类，它和它的实现类，也不需要存在"is-a"关系
 *          接口比抽象类的使用更加灵活。
 *      3.程序开发中将接口和它的实现类之间的关系，称之为"like-a"关系。
 *          只要是实现了Xxx的功能，就像Xxx。
 *          比如一个盒子/箱子,它不是空调
 *          但它只要实现了空调的功能,那它就像空调
 *
 *      4.接口表示一种开发标准，一种规范。
 *         表示对功能的扩展，它只关注行为，不关注属性。
 *
 *  @since 09:43
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        // SuperDog在本案例中,创建对象的方式有几种呢?
        SuperDog sc = new SuperDog();
        // sc是一个子类引用,访问范围是子类 + 父类,它最全能
        sc.superDogOnly();
        Dog d = new SuperDog();
        // d.walkUpright();
        ISkills is = new SuperDog();
        IA ia = new SuperDog();
        Animal a = new SuperDog();
    }
}

abstract class Animal {
    public abstract void shout();

    public void animalOnly() {
    }
}

class Cat extends Animal {
    @Override
    public void shout() {
        System.out.println("猫叫");
    }
}

class Dog extends Animal {
    @Override
    public void shout() {
        System.out.println("狗叫");
    }

    public void dogOnly() {
    }
}

class SuperDog extends Dog implements ISkills, IA {
    @Override
    public void walkUpright() {
        System.out.println("你是单身狗,我现在可以直立行走!");
    }

    public void superDogOnly() {
    }
}

class SuperCat extends Cat implements ISkills {
    @Override
    public void walkUpright() {
        System.out.println("我是超威蓝猫,我现在可以直立行走!");
    }
}

// 该抽象类表示技能,实际上抽象类做不了这个事情
abstract class Skills {
    public abstract void walkUpright();
}

interface ISkills {
    public abstract void walkUpright();
}

interface IA {
}